# -*- coding:utf-8 -*-
#!/bin/sh

''''which python  >/dev/null && exec python  "$0" "$@" # '''

# Copyright (C) 2014-2015 Nginx, Inc.

# Example of an application working on port 9000
# To interact with nginx-ldap-auth-daemon this application
# 1) accepts GET  requests on /login and responds with a login form
# 2) accepts POST requests on /login, sets a cookie, and responds with redirect

import sys, os, signal, base64, cgi
if sys.version_info.major == 2:
    from urlparse import urlparse
    from Cookie import BaseCookie
    from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
elif sys.version_info.major == 3:
    from urllib.parse import urlparse
    from http.cookies import BaseCookie
    from http.server import HTTPServer, BaseHTTPRequestHandler

Listen = ('localhost', 9000)

import threading
if sys.version_info.major == 2:
    from SocketServer import ThreadingMixIn
elif sys.version_info.major == 3:
    from socketserver import ThreadingMixIn


def ensure_bytes(data):
    return data if sys.version_info.major == 2 else data.encode("utf-8")


class AuthHTTPServer(ThreadingMixIn, HTTPServer):
    pass

class AppHandler(BaseHTTPRequestHandler):

    def do_GET(self):

        url = urlparse(self.path)

        if url.path.startswith("/login"):
            return self.auth_form()

        self.send_response(200)
        self.end_headers()
        self.wfile.write(ensure_bytes('Hello, world! Requested URL: ' + self.path + '\n'))


    # send login form html
    def auth_form(self, target = None):

        # try to get target location from header
        if target == None:
            target = self.headers.get('X-Target')

        # form cannot be generated if target is unknown
        if target == None:
            self.log_error('target url is not passed')
            self.send_response(500)
            return

        html="""
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>认证页面</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="description" content="">
        <meta name="author" content="">
        <style>
            html,
            body,
            div,
            span,
            applet,
            object,
            iframe,
            h1,
            h2,
            h3,
            h4,
            h5,
            h6,
            p,
            blockquote,
            pre,
            a,
            abbr,
            acronym,
            address,
            big,
            cite,
            code,
            del,
            dfn,
            em,
            img,
            ins,
            kbd,
            q,
            s,
            samp,
            small,
            strike,
            strong,
            sub,
            sup,
            tt,
            var,
            u,
            i,
            center,
            dl,
            dt,
            dd,
            ol,
            ul,
            li,
            fieldset,
            form,
            label,
            legend,
            table,
            caption,
            tbody,
            tfoot,
            thead,
            tr,
            th,
            td,
            article,
            aside,
            canvas,
            details,
            embed,
            figure,
            figcaption,
            footer,
            header,
            hgroup,
            menu,
            nav,
            output,
            ruby,
            section,
            summary,
            time,
            mark,
            audio,
            video {
                margin: 0;
                padding: 0;
                border: 0;
                font-size: 100%;
                font: inherit;
                vertical-align: baseline;
            }

            /* ------- HTML5 display-role reset for older browsers ------- */

            article,
            aside,
            details,
            figcaption,
            figure,
            footer,
            header,
            hgroup,
            menu,
            nav,
            section {
                display: block;
            }

            body {
                line-height: 1;
            }

            ol,
            ul {
                list-style: none;
            }

            blockquote,
            q {
                quotes: none;
            }

            blockquote:before,
            blockquote:after,
            q:before,
            q:after {
                content: '';
                content: none;
            }

            table {
                border-collapse: collapse;
                border-spacing: 0;
            }
        </style>
        <style>
            body {
                width: 100vw;
                height: 100vh;
                overflow: hidden;
                font-family: "Microsoft YaHei", 微软雅黑, "Microsoft JhengHei", 华文细黑, STHeiti, MingLiu;
                text-align: center;
                color: #fff;
                background:url('http://www.88meitu.com/uploads/allimg/170327/5-1F220150505.jpg');
                background-size: 100% 100%;
                background-repeat:no-repeat;
            }

            .page-container {
                margin: 120px auto 0 auto;
            }

            h1 {
                font-size: 30px;
                font-weight: 700;
                text-shadow: 0 1px 4px rgba(0, 0, 0, .2);
            }

            form {
                position: relative;
                width: 305px;
                margin: 15px auto 0 auto;
                text-align: center;
            }

            input {
                width: 270px;
                height: 42px;
                line-height: 42px;
                margin-top: 25px;
                padding: 0 15px;
                background: #2d2d2d;
                /* browsers that don't support rgba */
                *background-color: transparent;
                background: rgba(45, 45, 45, .15);
                -moz-border-radius: 6px;
                -webkit-border-radius: 6px;
                border-radius: 6px;
                border: 1px solid #3d3d3d;
                /* browsers that don't support rgba */
                border: 1px solid rgba(255, 255, 255, .15);
                -moz-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset;
                -webkit-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset;
                box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset;
                font-family: 'PT Sans', Helvetica, Arial, sans-serif;
                font-size: 14px;
                color: #fff;
                text-shadow: 0 1px 2px rgba(0, 0, 0, .1);
                -o-transition: all .2s;
                -moz-transition: all .2s;
                -webkit-transition: all .2s;
                -ms-transition: all .2s;
            }

            input:-moz-placeholder {
                color: #fff;
            }

            input:-ms-input-placeholder {
                color: #fff;
            }

            input::-webkit-input-placeholder {
                color: #fff;
            }

            input:focus {
                outline: none;
                -moz-box-shadow:
                    0 2px 3px 0 rgba(0, 0, 0, .1) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                -webkit-box-shadow:
                    0 2px 3px 0 rgba(0, 0, 0, .1) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                box-shadow:
                    0 2px 3px 0 rgba(0, 0, 0, .1) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
            }

            .button {
                cursor: pointer;
                width: 300px;
                height: 44px;
                margin-top: 25px;
                padding: 0;
                background: #ef4300;
                -moz-border-radius: 6px;
                -webkit-border-radius: 6px;
                border-radius: 6px;
                border: 0px;
                -moz-box-shadow:
                    0 15px 30px 0 rgba(255, 255, 255, .25) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                -webkit-box-shadow:
                    0 15px 30px 0 rgba(255, 255, 255, .25) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                box-shadow:
                    0 15px 30px 0 rgba(255, 255, 255, .25) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                font-family: 'PT Sans', Helvetica, Arial, sans-serif;
                font-size: 14px;
                font-weight: 700;
                color: #fff;
                text-shadow: 0 1px 2px rgba(0, 0, 0, .1);
                -o-transition: all .2s;
                -moz-transition: all .2s;
                -webkit-transition: all .2s;
                -ms-transition: all .2s;
            }

            .button:hover {
                -moz-box-shadow:
                    0 15px 30px 0 rgba(255, 255, 255, .15) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                -webkit-box-shadow:
                    0 15px 30px 0 rgba(255, 255, 255, .15) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                box-shadow:
                    0 15px 30px 0 rgba(255, 255, 255, .15) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
            }

            .button:active {
                -moz-box-shadow:
                    0 15px 30px 0 rgba(255, 255, 255, .15) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                -webkit-box-shadow:
                    0 15px 30px 0 rgba(255, 255, 255, .15) inset,
                    0 2px 7px 0 rgba(0, 0, 0, .2);
                box-shadow:
                    0 5px 8px 0 rgba(0, 0, 0, .1) inset,
                    0 1px 4px 0 rgba(0, 0, 0, .1);

                border: 0px solid #ef4300;
            }

            .connect {
                width: 800px;
                margin: 50px auto 0 auto;
                font-size: 14px;

                text-shadow: 0 1px 3px rgba(0, 0, 0, .2);
            }

            .connect p {
                position: relative;
                left: -140%;
                top: 0
            }

            .connect a {
                display: inline-block;
                width: 32px;
                height: 35px;
                margin-top: 15px;
                -o-transition: all .2s;
                -moz-transition: all .2s;
                -webkit-transition: all .2s;
                -ms-transition: all .2s;
            }

            .alert {
                width: 310px;
                height: 200px;
                background: #000;
                position: absolute;
                top: -40%;
                left: 50%;
                margin: -101px 0 0 -151px;
            }

            .alert h2 {
                height: 40px;
                padding-left: 8px;
                font-size: 14px;
                background: #FF0543;
                text-align: left;
                line-height: 40px;
            }

            .alert .alert_con {
                background: #fff;
                height: 160px;
            }

            .alert .alert_con p {
                color: #000;
                line-height: 90px;
            }

            .alert .alert_con .btn {
                padding: 3px 10px;
                color: #fff;
                cursor: pointer;
                background: #72D1FF;
                border: 1px solid #72D1FF;
                border-radius: 4px;
            }

            .alert .alert_con .btn:hover {
                background: #4FB2EF;
                border: 1px solid #4FB2EF;
                border-radius: 4px;
            }
        </style>
    </head>
    <body>
        <div class="page-container">
            <h1>你和该网站的连接需要进行认证</h1>
            <form action="/login" method="post">
                <div>
                    <input type="text" class="username" name="username" placeholder="请输入账号" autocomplete="off" />
                </div>
                <div>
                    <input type="password" name="password" class="password" placeholder="请输入密码" />
                </div>
                <input type="hidden" name="target" value="TARGET">
                <input class="button" type="submit" value="下一步" />
            </form>
            
        </div>
    </body>
</html>
"""

        self.send_response(200)
        self.end_headers()
        self.wfile.write(ensure_bytes(html.replace('TARGET', target)))


    # processes posted form and sets the cookie with login/password
    def do_POST(self):

        # prepare arguments for cgi module to read posted form
        env = {'REQUEST_METHOD':'POST',
               'CONTENT_TYPE': self.headers['Content-Type'],}

        # read the form contents
        form = cgi.FieldStorage(fp = self.rfile, headers = self.headers,
                                environ = env)
        

        # extract required fields
        user = form.getvalue('username')
        passwd = form.getvalue('password')
        target = form.getvalue('target')
        client_ip = self.headers.get('X-Real-IP')
        print(self.headers)
        if user != None and passwd != None and target != None:

            # form is filled, set the cookie and redirect to target
            # so that auth daemon will be able to use information from cookie

            self.send_response(302)

            # WARNING WARNING WARNING
            #
            # base64 is just an example method that allows to pack data into
            # a cookie. You definitely want to perform some encryption here
            # and share a key with auth daemon that extracts this information
            #
            # WARNING WARNING WARNING
            import time
            #设置过期时间为2小时
            expires = time.time() + 2 * 3600
            date = time.strftime("%a, %d-%b-%Y %T", time.gmtime(expires))
            enc = base64.b64encode(ensure_bytes(user + ':' + passwd + ':' + client_ip))
            if sys.version_info.major == 3:
                enc = enc.decode()
            #self.send_header('Set-Cookie', b'nginxauth=' + enc + b'; httponly')
            self.send_header('Set-Cookie', b'nginxauth=' + enc + b';' + b'expires=' + date + b'; + httponly')
            self.send_header('Location', target)
            self.end_headers()

            return

        self.log_error('some form fields are not provided')
        self.auth_form(target)


    def log_message(self, format, *args):
        if len(self.client_address) > 0:
            addr = BaseHTTPRequestHandler.address_string(self)
        else:
            addr = "-"

        sys.stdout.write("%s - - [%s] %s\n" % (addr,
                         self.log_date_time_string(), format % args))

    def log_error(self, format, *args):
        self.log_message(format, *args)


def exit_handler(signal, frame):
    sys.exit(0)

if __name__ == '__main__':
    server = AuthHTTPServer(Listen, AppHandler)
    signal.signal(signal.SIGINT, exit_handler)
    server.serve_forever()
